﻿using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using CTP.Command;
using CTP.Entitys;
using CTP.Utilty;

namespace CTP.Session
{
    /// <summary>
    /// 功能：对话中的回调处理，本类负责持有回调接口列表
    ///       当接收到柜台回报时，把回报发送到回调接口列表中全部回调接口
    /// 创建：陈粤雄 2012-5-5
    /// </summary>
    internal class ResponseManager
    {
        #region 字段
        /// <summary>
        /// ResponseManager的实例
        /// </summary>
        private static ResponseManager m_Instance;

        /// <summary>
        /// 当前已注册的回调接口的列表，可以允许一个账号有多个回调接口
        /// </summary>
        private ConcurrentBag<ICTPCallbackHandle> m_AllCallback = new ConcurrentBag<ICTPCallbackHandle>();

        /// <summary>
        /// 要回调的命令的队列
        /// </summary>
        private ConcurrentQueue<IResponseCommand> m_cmdQueue = new ConcurrentQueue<IResponseCommand>();

        /// <summary>
        /// 处理回调的线程，为避免柜台堵塞，要用一个新的线程处理回调
        /// </summary>
        private Thread m_dequeueThread;

        /// <summary>
        /// COM的处理方法
        /// </summary>
        public const string COM_CALLBACK = "_COM_CALLBACK";

        #endregion

        #region 属性
        /// <summary>
        /// 获取ResponseManager的实例
        /// </summary>
        public static ResponseManager Instance { get { return m_Instance; } }

        #endregion

        #region 构造
        /// <summary>
        /// 静态构造函数，在这里初始化静态成员
        /// </summary>
        static ResponseManager()
        {
            m_Instance = new ResponseManager();
        }

        /// <summary>
        /// 私有构造函数，保证只有一个实例
        /// </summary>
        private ResponseManager()
        {
            m_dequeueThread = new Thread(new ThreadStart(procQueue));
            m_dequeueThread.IsBackground = true;
            m_dequeueThread.Start();
        }

        /// <summary>
        /// 处理回调队列
        /// </summary>
        private void procQueue()
        {
            IResponseCommand cmd;
            while (true)
            {
                while (m_cmdQueue.TryDequeue(out cmd))
                {
                    foreach (ICTPCallbackHandle callback in m_AllCallback)
                    {
                        dispathCmd(callback, cmd);
                    }
                }

                Thread.Sleep(1);
            }
        }

        /// <summary>
        /// 在指定线程上分发一个命令
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="cmd"></param>
        private void dispathCmd(ICTPCallbackHandle callback, IResponseCommand cmd)
        {
            if (callback == null)
            {
                Logger.Instance.WriteInfo("客户端已断开...");
                return;
            }
            try
            {
                if (cmd is ErrorEventCmd)
                {
                    ErrorEventCmd c = cmd as ErrorEventCmd;
                    callback.OnError(c.ReturnInfo, c.RequestID);
                }
                else if (cmd is LoginEventCmd)
                {
                    LoginEventCmd c = cmd as LoginEventCmd;
                    callback.OnLogin(c.ReturnInfo, c.LoginInfo, c.RequestID);
                }
                else if (cmd is LogoutEventCmd)
                {
                    LogoutEventCmd c = cmd as LogoutEventCmd;
                    callback.OnLogout(c.ReturnInfo, c.TradingAccount, c.RequestID);
                }
                else if (cmd is LoginQouteEventCmd)
                {
                    LoginQouteEventCmd c = cmd as LoginQouteEventCmd;
                    callback.OnLoginQoute(c.ReturnInfo, c.LoginInfo, c.RequestID);
                }
                else if (cmd is LogoutQouteEventCmd)
                {
                    LogoutQouteEventCmd c = cmd as LogoutQouteEventCmd;
                    callback.OnLogoutQoute(c.ReturnInfo, c.TradingAccount, c.RequestID);
                }
                else if (cmd is AccountSummaryEventCmd)
                {
                    AccountSummaryEventCmd c = cmd as AccountSummaryEventCmd;
                    callback.OnAccountSummary(c.ReturnInfo, c.AccountInformation, c.RequestID);
                }
                else if (cmd is OrderStatusEventCmd)
                {
                    OrderStatusEventCmd c = cmd as OrderStatusEventCmd;
                    callback.OnOrderStatus(c.ReturnInfo, c.OrderStatus, c.RequestID);
                }
                else if (cmd is OrderFilledEventCmd)
                {
                    OrderFilledEventCmd c = cmd as OrderFilledEventCmd;
                    callback.OnOrderFilled(c.ReturnInfo, c.OrderReport);
                }
                else if (cmd is QuerySettlementInfoEventCmd)
                {
                    QuerySettlementInfoEventCmd c = cmd as QuerySettlementInfoEventCmd;
                    callback.OnQuerySettlementInfo(c.ReturnInfo, c.ConfirmInfo, c.RequestID);
                }
                else if (cmd is ConfirmSettlementInfoEventCmd)
                {
                    ConfirmSettlementInfoEventCmd c = cmd as ConfirmSettlementInfoEventCmd;
                    callback.OnConfirmSettlementInfo(c.ReturnInfo, c.RequestID);
                }
                else if (cmd is QueryPositionEventCmd)
                {
                    QueryPositionEventCmd c = cmd as QueryPositionEventCmd;
                    callback.OnPosition(c.ReturnInfo, c.Positions, c.RequestID);
                }
                else if (cmd is QueryOrderEventCmd)
                {
                    QueryOrderEventCmd c = cmd as QueryOrderEventCmd;
                    callback.OnQueryOrder(c.ReturnInfo, c.Orders, c.RequestID);
                }
                else if (cmd is HistoricalOrderEventCmd)
                {
                    HistoricalOrderEventCmd c = cmd as HistoricalOrderEventCmd;
                    callback.OnHistoricalOrder(c.ReturnInfo, c.Orders, c.RequestID);
                }
                else if (cmd is QueryFilledEventCmd)
                {
                    QueryFilledEventCmd c = cmd as QueryFilledEventCmd;
                    callback.OnQueryFilled(c.ReturnInfo, c.OrderReports, c.RequestID);
                }
                else if (cmd is HistoricalFilledEventCmd)
                {
                    HistoricalFilledEventCmd c = cmd as HistoricalFilledEventCmd;
                    callback.OnHistoricalFilled(c.ReturnInfo, c.OrderReports, c.RequestID);
                }
                else if (cmd is QouteEventCmd)
                {
                    QouteEventCmd c = cmd as QouteEventCmd;
                    callback.OnQoute(c.QouteInfo);
                }
            }
            catch (System.Exception ex)
            {
                Logger.Instance.WriteInfo("发送回报失败," + ex.GetBaseException() + ",cmd:" + cmd);
            }
        }
        #endregion

        #region 公开方法
        /// <summary>
        /// 注册指定资金账号的回调接口
        /// </summary>
        /// <param name="tradingAccount"></param>
        /// <param name="callback"></param>
        public void RegisterCallback(ICTPCallbackHandle callback)
        {
            if (callback == null)
                return;

            m_AllCallback.Add(callback);
            Logger.Instance.WriteDebug(string.Format("已注册回调接口，回调接口{0}", callback.ToString()));

        }

        /// <summary>
        /// 卸载指定资金账号的回调接口
        /// </summary>
        /// <param name="tradingAccount"></param>
        /// <param name="callback"></param>
        public void UnRegisterCallback(ICTPCallbackHandle callback)
        {
            if (callback == null)
                return;

            m_AllCallback.TryTake(out callback);
        }

        public void OnError(string tradingAccount, ReturnInfo result, int requestID)
        {
            ErrorEventCmd cmd = new ErrorEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                RequestID = requestID
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnLogin(string tradingAccount, ReturnInfo result, LoginInfo loginInfo, int requestId)
        {
            LoginEventCmd cmd = new LoginEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                LoginInfo = loginInfo,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnLogout(string tradingAccount, ReturnInfo result, int requestId)
        {
            LogoutEventCmd cmd = new LogoutEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnLoginQoute(string tradingAccount, ReturnInfo result, LoginInfo loginInfo, int requestId)
        {
            LoginQouteEventCmd cmd = new LoginQouteEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                LoginInfo = loginInfo,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnLogoutQoute(string tradingAccount, ReturnInfo result, int requestId)
        {
            LogoutQouteEventCmd cmd = new LogoutQouteEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnAccountSummary(string tradingAccount, ReturnInfo result, AccountInformation summary, int requestId)
        {
            AccountSummaryEventCmd cmd = new AccountSummaryEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                AccountInformation = summary,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnOrderStatus(string tradingAccount, ReturnInfo result, OrderStatus ord, int requestId)
        {
            OrderStatusEventCmd cmd = new OrderStatusEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                OrderStatus = ord,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnOrderFilled(string tradingAccount, ReturnInfo result, OrderReport ord)
        {
            OrderFilledEventCmd cmd = new OrderFilledEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                OrderReport = ord,
                RequestID = -1
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnQuerySettlementInfo(string tradingAccount, SettlementInfoConfirm ConfirmInfo, ReturnInfo result, int requestId)
        {
            QuerySettlementInfoEventCmd cmd = new QuerySettlementInfoEventCmd()
            {
                ConfirmInfo = ConfirmInfo,
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnConfirmSettlementInfo(string tradingAccount, ReturnInfo result, int requestId)
        {
            ConfirmSettlementInfoEventCmd cmd = new ConfirmSettlementInfoEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnPosition(string tradingAccount, ReturnInfo result, PositionInformation[] positions, int requestId)
        {
            QueryPositionEventCmd cmd = new QueryPositionEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                Positions = positions,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnQueryOrder(string tradingAccount, ReturnInfo result, Order[] orders, int requestId)
        {
            QueryOrderEventCmd cmd = new QueryOrderEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                Orders = orders,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnHistoricalOrder(string tradingAccount, ReturnInfo result, Order[] orders, int requestId)
        {
            HistoricalOrderEventCmd cmd = new HistoricalOrderEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                Orders = orders,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnQueryFilled(string tradingAccount, ReturnInfo result, OrderReport[] orders, int requestId)
        {
            QueryFilledEventCmd cmd = new QueryFilledEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                OrderReports = orders,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnHistoricalFilled(string tradingAccount, ReturnInfo result, OrderReport[] orders, int requestId)
        {
            HistoricalFilledEventCmd cmd = new HistoricalFilledEventCmd()
            {
                TradingAccount = tradingAccount,
                ReturnInfo = result,
                OrderReports = orders,
                RequestID = requestId
            };
            m_cmdQueue.Enqueue(cmd);
        }

        public void OnQoute(QouteInfo qouteInfo)
        {
            QouteEventCmd cmd = new QouteEventCmd()
            {
                QouteInfo = qouteInfo
            };
            m_cmdQueue.Enqueue(cmd);
        }
        #endregion
    }
}
